#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
#include <limits.h>
#include <sys/socket.h>
#include <sys/un.h>
#include "ipc_def.h"
#include "job_schd.h"

/*
 * "They have no protocol processing to perform, no network headers
 * to add or remove, no checksums to calculate, no sequence numbers
 * to generate, and no acknowlegements to send."
 * "Messages are neither lost nor delivered out of order."
 */

int prior = 0;
char *fpath = NULL;
char *fargs[ARGS_NUM] = {0};
int cli_sockfd;

void print_usage(int exit_status)
{
    fprintf(stderr, "Usage: enq [-p num] exec_file_path [args]\n");
    fprintf(stderr, USAGE_IDENT "-p specify the expected priority of the newly created job which would default to 0 when unspecified or specified but unvalid.\n");
    fprintf(stderr, USAGE_IDENT "File path must be absolute.\n");
    fprintf(stderr, USAGE_IDENT "No more than %d instead of %d arguments can be specified.\n", ARGS_NUM, ARG_MAX);
    exit(exit_status);
}

void init_args(int argc, char *argv[])
{
    int i, j;
    if (argc < 2) {
        print_usage(EXIT_FAILURE);
    }
    i = 1;
    if (!strcmp(argv[1], "-p")) {
        if ((prior = atoi(argv[2])) < 0) {
            fprintf(stderr, "priority number is unvalid.\n");
            print_usage(EXIT_FAILURE);
        }
        prior = (prior < MIN_PRIO || prior > MAX_PRIO) ? 0 : prior;
        i = 3;
    }
    if (!access(argv[i], X_OK)) {
        fpath = strdup(argv[i]);
        i++;
    }
    else {
        fprintf(stderr, "specified file is not executable.\n");
        print_usage(EXIT_FAILURE);
    }
    for (j = 0; i < argc; i++) {
        if (i >= ARGS_NUM) {
            fprintf(stderr, "too much args for exec_file_path are specified.\n");
            print_usage(EXIT_FAILURE);
        }
        fargs[j++] = strdup(argv[i]);
    }
    fargs[j] = NULL;
}

/*
 * tag_len of send_item would be converted to unsigned char automatically.
 */
void send_enq_info(void)
{
    char byte;
    uid_t euid;
    int i = 0;

    byte = OP_ENQ;
    send_item(cli_sockfd, TAG_OPCODE, sizeof(unsigned char), &byte);

    euid = geteuid();
    send_item(cli_sockfd, TAG_UID, sizeof(uid_t), (char *)&euid);

    byte = (unsigned char)prior;
    send_item(cli_sockfd, TAG_PRIOR, sizeof(unsigned char), &byte);

    send_item(cli_sockfd, TAG_PATH, strlen(fpath), fpath);

    while (fargs[i]) {
        send_item(cli_sockfd, TAG_ARGS, strlen(fargs[i]), fargs[i]);
        i++;
    }

    send_item(cli_sockfd, TAG_END, 0, NULL);
}

int main(int argc, char *argv[])
{
    init_args(argc, argv);
    if ((cli_sockfd = init_conn()) < 0) {
        fprintf(stderr, "%d, calling init_conn failed: %s.\n", cli_sockfd, strerror(errno));
        exit(EXIT_FAILURE);
    }
    send_enq_info();
    close(cli_sockfd);
    return 0;
}

